/*
 * Copyright (C) 2007-2010 Crise, crise<at>mail.berlios.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "stdafx.h"
#include "MPPlugin.h"
#include "MPPluginDlg.h"

#include <MediaPlayersLib/MediaPlayersLib.h>

MPPlugin* MPPlugin::instance = NULL;

DCUtilsPtr MPPlugin::utils = NULL;

Bool MPPlugin::onLoad(DCCorePtr core, bool install) {
	dcpp = core;
	hooks = (DCHooksPtr)core->query_interface(DCINTF_HOOKS, DCINTF_HOOKS_VER);

	config = (DCConfigPtr)core->query_interface(DCINTF_CONFIG, DCINTF_CONFIG_VER);
	if(!config) return False;

	utils = (DCUtilsPtr)core->query_interface(DCINTF_DCPP_UTILS, DCINTF_DCPP_UTILS_VER);
	if(!utils) return False;

	Util::initialize(MPPlugin::toWide, MPPlugin::fromWide);

	if(install) {
		// Default settings
		setOption("WMPSpam", "/me playing: %[title] at %[bitrate] <Windows Media Player %[version]>");
		setOption("iTunesSpam", "/me playing: %[title] at %[bitrate] <iTunes %[version]>");
		setOption("MPCSpam", "/me playing: %[title] <Media Player Classic>");
		setOption("BarPlayer", "winamp");
		setOption("ShowBar", false);

		// These two are hidden settings (might be made visible later)
		setOption("EnableMSN", true);
		setOption("MSNSpam", "/me playing: %[format]");
	}

	if(getBoolOption("EnableMSN"))
		MediaPlayersLib::createMSNGhost();

	events[HOOK_UI_CREATED] = hooks->bind_hook(HOOK_UI_CREATED, &MPPlugin::onUiCreated, NULL);

	// Demonstrate another way to pass interfaces around...
	DCHubPtr hub = NULL;
	if((hub = (DCHubPtr)core->query_interface(DCINTF_DCPP_HUBS, DCINTF_DCPP_HUBS_VER)) != NULL) {
		events[HOOK_UI_CHAT_COMMAND] = hooks->bind_hook(HOOK_UI_CHAT_COMMAND, &MPPlugin::onChatCommand, hub);
		events[HOOK_UI_CHAT_COMMAND_PM] = hooks->bind_hook(HOOK_UI_CHAT_COMMAND_PM, &MPPlugin::onChatCommandPM, hub);
	}

	return True;
}

Bool MPPlugin::onUnload() {
	// Clean up the ghost window
	if(getBoolOption("EnableMSN"))
		MediaPlayersLib::createMSNGhost();

	// In case uninstalled
	if(IsWindow(mainWnd) && mediaBand != -1) {
		SendMessage(hWndRebar, RB_DELETEBAND, mediaBand, 0);
		ctrlMediaBar.DestroyWindow();
	}

	mediabarImages.Destroy();

	for(auto i = events.begin(); i != events.end(); ++i)
		hooks->release_hook(i->second);

	return (mainWnd && IsWindow(mainWnd)) ? False : True; 
}

Bool MPPlugin::processCommand(dcptr_t pObject, CommandDataPtr cmd, DCHubPtr hub, bool isPrivate) {
	string result = "";
	bool failed = false;

	if(MPPlugin::getInstance()->parseCommand(cmd->command, cmd->params, result, failed)) {
		if(!failed) {
			Bool thirdPerson = False;
			if(strnicmp(result.c_str(), "/me ", 4) == 0) {
				thirdPerson = True;
				result = result.substr(4);
			}
			if(isPrivate)
				hub->send_private_message((UserDataPtr)pObject, result.c_str(), thirdPerson);
			else
				hub->send_message((HubDataPtr)pObject, result.c_str(), thirdPerson);
		} else if(!isPrivate) {
			hub->local_message((HubDataPtr)pObject, result.c_str(), MSG_SYSTEM);
		}
		return True;
	}
	return False;
}

Bool MPPlugin::onConfig(HWND hWnd) {
	MPPluginDlg dlg(this);

	bool oldShow = getBoolOption("ShowBar");
	bool oldMSN = getBoolOption("EnableMSN");
	if(dlg.DoModal(hWnd) == IDOK) {
		if(getBoolOption("ShowBar") != oldShow && mediaBand != -1)
			SendMessage(hWndRebar, RB_SHOWBAND, mediaBand, !oldShow ? TRUE : FALSE);

		if(getBoolOption("EnableMSN") != oldMSN)
			MediaPlayersLib::createMSNGhost();
	}
	return True;
}

void MPPlugin::onWindowActivated(HWND hWnd) {
	// We don't want to do this more than once
	if(mediaBand != -1) return;

	// ApexDC++ has only one rebarcontrol, lucky us
	hWndRebar = FindWindowEx(hWnd, NULL, REBARCLASSNAME, NULL);
	if(hWndRebar == NULL) return;

	// Create the toolbar and add buttons
	mediabarImages.CreateFromImage(IDB_MEDIABAR, 20, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_SHARED);
	ctrlMediaBar.Create(hWnd, NULL, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST, 0, ATL_IDW_TOOLBAR);
	ctrlMediaBar.SetExtendedStyle(TBSTYLE_EX_MIXEDBUTTONS);
	ctrlMediaBar.SetImageList(mediabarImages);

	const int numButtons = 8;
	TBBUTTON tb[numButtons];
	memset(&tb, 0, sizeof(tb));
	int n = 0, bitmap = 0;

#define ADD_BUTTON(a, b) \
	tb[n].iBitmap = bitmap++; \
	tb[n].idCommand = a; \
	tb[n].fsState = TBSTATE_ENABLED; \
	tb[n].fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE; \
	tb[n].iString = ctrlMediaBar.AddStrings(_T(b)); \
	n++;

	// Need to use these to avoid possible conflicts
	// (hopefully there is no side effects)
	ADD_BUTTON(-2, "Back")
	ADD_BUTTON(-3, "Play")	
	ADD_BUTTON(-4, "Pause")
	ADD_BUTTON(-5, "Next")
	ADD_BUTTON(-6, "Stop")
	ADD_BUTTON(-7, "Volume Up")
	ADD_BUTTON(-8, "Volume Half / Mute")
	ADD_BUTTON(-9, "Volume Down")

#undef ADD_BUTTON

	ctrlMediaBar.SetButtonStructSize();
	ctrlMediaBar.AddButtons(numButtons, tb);
	ctrlMediaBar.AutoSize();

	// Add the toolbar and ensure no buttons in it ever get hidden
	mediaBand = (UINT)SendMessage(hWndRebar, RB_GETBANDCOUNT, 0, 0);
	CFrameWindowImplBase<>::AddSimpleReBarBandCtrl(hWndRebar, ctrlMediaBar.m_hWnd, 0, NULL, FALSE, 0, TRUE);

	// Let's ensure that the toolbar state is in sync with others
	REBARBANDINFO rbi;
	rbi.cbSize = sizeof(rbi);
	rbi.fMask  = RBBIM_STYLE;
	SendMessage(hWndRebar, RB_GETBANDINFO, 0, (LPARAM)&rbi);
	if((rbi.fStyle & RBBS_NOGRIPPER) == RBBS_NOGRIPPER) {
		rbi.fStyle &= ~RBBS_BREAK;
		SendMessage(hWndRebar, RB_SETBANDINFO, mediaBand, (LPARAM)&rbi);
	}

	// If user has chosen not to display mediabar hide it
	if(!getBoolOption("ShowBar"))
		SendMessage(hWndRebar, RB_SHOWBAND, mediaBand, FALSE);
}

void MPPlugin::onWindowNotify(LPARAM lParam) {
	// Need to do it like this to avoid possible conflicts
	LPNMHDR pnmh = (LPNMHDR)lParam;
	if(pnmh->code == NM_CLICK && pnmh->hwndFrom == ctrlMediaBar.m_hWnd)
		MediaPlayersLib::playerControl(getOption("BarPlayer"), ctrlMediaBar.HitTest(&((LPNMMOUSE)lParam)->pt));
}

bool MPPlugin::parseCommand(const char* cmd, const char* param, string& result, bool& status) {
	if(stricmp(cmd, "help") == 0) {
		if(stricmp(param, "plugins") == 0) {
			result =
				"\t\t\t Help: MediaPlayers \t\t\t\n"
				"\t /wmp \t\t\t\t Broadcast what's currently playing in Windows Media Player\n"
				"\t /itunes \t\t\t Broadcast what's currently playing in iTunes\n"
				"\t /mpc \t\t\t\t Broadcast what's currently playing in Media Player Classic\n"
				"\t /np \t\t\t\t Broadcast what's currently playing in any supported player\n";

			status = true;
			return true;
		}
	} else if(stricmp(cmd, "wmp") == 0) {
		result = MediaPlayersLib::getWMPSpam(getOption("WMPSpam"), status, mainWnd);
		return true;
	} else if(stricmp(cmd, "itunes") == 0) {
		result = MediaPlayersLib::getItunesSpam(getOption("iTunesSpam"), status);
		return true;
	} else if(stricmp(cmd, "mpc") == 0) {
		DWORD osMajor = LOBYTE(LOWORD(GetVersion()));
		result = (osMajor < 6) ? MediaPlayersLib::getMPCSpam(getOption("MPCSpam"), status) : MediaPlayersLib::getMSNSpam(getOption("MSNSpam"), status);
		return true;
	} else if(stricmp(cmd, "np") == 0) {
		// This is the generic command
		result = MediaPlayersLib::getWMPSpam(getOption("WMPSpam"), status, mainWnd);
		if(status) {
			status = false;
			result = MediaPlayersLib::getItunesSpam(getOption("iTunesSpam"), status);
		} if(status) {
			status = false;
			result = MediaPlayersLib::getMPCSpam(getOption("MPCSpam"), status);
		} if(status) {
			status = false;
			result = MediaPlayersLib::getMSNSpam(getOption("MSNSpam"), status);
		}
		return true;
	}

	return false;
}